import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'
// import { Observable } from 'rxjs'
import { Request } from 'express'
import { UserService } from '../user/user.service'
import { User } from '../user/user.entity'
import { Reflector } from '@nestjs/core'
import { Roles } from './roles.decorator'

// 作用：单纯角色鉴权=>需要先jwt鉴权，因为需要req.user
@Injectable()
export class AdminGuard implements CanActivate {
  // 常见的错误：在使用adminGuard时未导入UserModule
  constructor(
    protected userService: UserService,
    protected reflector: Reflector
  ) {}
  async canActivate(context: ExecutionContext): Promise<boolean> {
    //异步的变化
    // 1.获取请求对象
    /* context：指向当前请求上下文的对象 switchToHttp()：允许从 ExecutionContext 中切换到 HTTP 上下文，这样就可以访问 HTTP 请求和响应对象。
    getRequest<Request>()：该方法获取当前的 HTTP 请求对象，类型为 Request */
    const req = context.switchToHttp().getRequest<Request>() //import { Request } from 'express'
    // console.log('🚀 ~ AdminGuard ~ canActivate ~ req:', req.user)
    // 2.获取请求中的用户信息进行逻辑上的判断 => 角色判断
    const user = await this.userService.find((req.user as User).username)
    // console.log('🚀 ~ AdminGuard ~ canActivate ~ user:', user)
    // 获取动态传入的Roles:有权限的角色
    // this.reflector.get() 是 NestJS 中用于获取元数据（metadata）的一种方式。它基于 反射（reflection）机制，通常结合 @nestjs/core 的 Reflector 类来使用
    const powerRoles = this.reflector.get(Roles, context.getHandler())
    // console.log('🚀 ~ AdminGuard ~ canActivate ~ powerRoles:', powerRoles)

    // 普通用户=>后面可加入更多的逻辑
    // filter：用于根据条件筛选数组中的元素，并返回符合条件的元素组成的新数组。
    if (user) {
      //some：判断数组中是否至少有一个元素满足条件
      //includes：判断数组中是否包含特定的元素
      //some方法遍历数组，将数组中的元素给了includes()方法，includes方法就判断在userRoles是否有some遍历的元素，有的话即返回ture，而some就知道了powerRoles数组中至少有一个满足了条件，则也返回ture
      // 提取出所有角色的id字段，生成一个userRoles数组
      const userRoles = user.roles.map((o) => o.id)
      console.log('🚀 ~ AdminGuard ~ canActivate ~ userRoles:', userRoles)
      console.log('🚀 ~ AdminGuard ~ canActivate ~ powerRoles:', powerRoles)

      // 检查用户是否有任何一个角色在允许的角色列表（allowedRoles）
      // 判断userRoles(用户的所有角色)里是否包含了powerRoles(授权的角色)的id
      // userRoles只要其中一个是授权角色就好，使用some  powerRoles=[1,2,3] userRoles[1]
      const hasAccess = powerRoles.some((role) => userRoles.includes(role))
      if (hasAccess) return true
    }
    return false
  }
}
